using System;
using System.Collections.Generic;
using System.Linq;

public class Beer {
    public virtual String Variety { get; set; }
    public virtual DateTime BrewDate { get; set; }
    public virtual Double ABV { get; set; }
    private Dictionary<String, Object> getValueEquality() {
        return new Dictionary<String, Object> {
            {"Variety", Variety},
            {"BrewDate", BrewDate}};
    }
    override public Boolean Equals(Object other) {
        var o = other as Beer;
        return ValueEquality.Equals(getValueEquality(), o.getValueEquality());
    }
    override public Int32 GetHashCode() {
        return ValueEquality.Hash(getValueEquality());
    }
    override public String ToString() {
        return String.Format("Beer ({0}, {1} abv, brewed on {2})", Variety, ABV, BrewDate);
    }
}

public class Bottle {
    public virtual Int32 Serial { get; set; }
    public virtual Beer Contents { get; set; }
    override public Boolean Equals(Object other) {
        var o = other as Bottle;
        if (Object.ReferenceEquals(o, null)) return false;
        return Serial.Equals(o.Serial);
    }
    override public Int32 GetHashCode() {
        return Serial.GetHashCode();
    }
    override public String ToString() {
        return String.Format("Bottle #{0} ({1})", Serial, Contents);
    }
}

public static class ValueEquality {
    public static Boolean Equals(Dictionary<String, Object> a, Dictionary<String, Object> b) {
        if ((a == null) ^ (b == null)) return false;
        if (a.Count != b.Count) return false;
        foreach (String k in a.Keys) {
            if (!a[k].Equals(b[k])) return false;
        }
        return true;
    }
    public static Int32 Hash(Dictionary<String, Object> valueEquality) {
        return
            Enumerable.Aggregate(
                valueEquality,
                0,
                (a, p) => {
                    unchecked {
                        return (a << 5) ^ (a >> 27) ^ p.Value.GetHashCode();
                    }
                });
    }
}
